<template>
	<zh-sheet :color="props.color" :height="props.height" :padding="[0, 0]">
		<zh-sheet :color="props.color" text :round="3" :border="0" _class="flex flex-row overflow" :height="68"
			:margin="[0, 0]" :padding="[24, 0]">
			<view style="height: 68rpx" class="flex flex-row flex-row-center-start">
				<view v-for="(item, index) in _valueArrays" :key="index" class="flex flex-row flex-row-center-start">
					<view>
						<zh-text :followTheme="_activeIndex == index ? props.followTheme : false" :fontSize="28"
							_class="text-overflow-1" :color="_activeIndex == index ? props.activeColor : ''"
							:label="item" @click="tabClick(index)"></zh-text>
					</view>
					<view class="mx-10" v-if="index < _valueArrays.length - 1">
						<zh-text :followTheme="props.followTheme" :label="props.separator ? props.separator : '/'"
							:fontSize="24" :color="props.activeColor">
						</zh-text>
					</view>
				</view>
				<zh-text :followTheme="_activeIndex == _nowLevel ? props.followTheme : false"
					:color="_activeIndex == _nowLevel ? props.activeColor : ''" v-if="_nowLevel == _idArrays.length"
					:fontSize="28" _class="ml-10" label=">请选择" @click="tabClick(_nowLevel)"></zh-text>
			</view>
		</zh-sheet>

		<view style="height: 16rpx"></view>
		<view v-if="slotTabHeigth" class="flex flex-row flex-row-center-start">
			<slot></slot>
		</view>
		<view style="height: 16rpx"></view>
		<BaseCascader :followTheme="props.followTheme" :color="props.activeColor" :fieldNames="_fieldNames"
			:height="props.height - 120 - slotTabHeigth" :data="listData" :beforeCellClick="props.beforeCellClick"
			@cell-click="emits('cell-click', $event)"></BaseCascader>
	</zh-sheet>
</template>
<script lang="ts" setup>
	/**
 * 级联选择(点选)
 * @description 级联选择有很多用处，不管是地址选择，城市或者自定数据关联选择，都非常有用处。
 */
	import { computed, provide, ref, toRaw, watch, Ref, nextTick, isRef, isProxy, PropType, onMounted } from 'vue'
	import BaseCascader from './base-cascader.vue';
	import { childrenData } from './interface'
	import http from '@/common/utils/http';
	import { getNodeRouterData, getNodeRouterCustomStr, queryNodeIsParent } from './util'
	/**
	 * 事件说明。
	 * @update:modelValue 为v-model
	 * @tab-click 点击切换tab触发。
	 * @cell-click 点击项目时触发
	 * @change 最后选中值时触发，结果同v-model
	 */
	const emits = defineEmits(['update:modelValue', 'update:modelStr', 'tab-click', 'cell-click', 'change'])
	const props = defineProps({
		//转义的字段
		fieldNames: {
			type: Object,
			default: () => {
				return { label: 'title', value: 'key', children: 'children' };
			},
		},
		//是否动态懒加载
		lazy: {
			type: Boolean,
			default: false,
		},
		//是否显示完整路径
		showAllLevels: {
			type: Boolean,
			default: true,
		},
		//是否返回所有路径值
		retAllLevels: {
			type: Boolean,
			default: true,
		},
		//分隔符
		separator: {
			type: String,
			default: '/',
		},
		timeout: Number,
		queryParams: {
			type: Object,
			default: () => { },
		},
		//查询附带参数
		searchParams: {
			type: Object,
			default() {
				return {
					tableName: 'sys_dict',
					resultList: [],
					queryList: [],
					pageNum: 1,
					pageSize: 20,
				};
			},
		},
		//查询url
		url: {
			type: String,
			default() {
				return '';
			},
		},
		//查询功能编号
		funcCode: {
			type: String,
			default() {
				return '';
			},
		},
		//查询数据字典字段
		dictField: {
			type: String,
			default() {
				return '';
			},
		},
		//查询主字段名称
		searchField: {
			type: String,
			default() {
				return '';
			},
		},
		followTheme: {
			type: [Boolean, String],
			default: true
		},
		/**
		 * 导入的数据
		 */
		data: {
			type: Array as PropType<Array<childrenData>>,
			default: () => [],
			required: true
		},
		/**
		 * 默认选中的数据
		 */
		defaultValue: {
			type: Array as PropType<Array<string>>,
			default: () => []
		},
		/**
		 * 双向绑定输入数据
		 */
		modelValue: {
			type: Array,
			default: () => []
		},
		height: {
			type: Number,
			default: 650
		},
		//激活状态下的颜色。
		activeColor: {
			type: String,
			default: 'primary'
		},
		// 背景主题
		color: {
			type: String,
			default: 'white'
		},
		//点击tab切换之前执行的勾子函数。可以是promise.返回假，即阻切换。真切换正常。方便动态加载数据。
		beforeTabClick: {
			type: [Function, Boolean],
			default: () => {
				return false
			}
		},
		//点击列表中项目时再自动切换到下一项时之前执行的勾子函数，方便动态加载数据。
		beforeCellClick: {
			type: [Function, Boolean],
			default: () => {
				return false
			}
		},
		//介于tab和下面选项中间的插槽区域。如果想自定内容在这这间，可以设置高度，将会显示 。
		slotTabHeigth: {
			type: Number,
			default: 0
		}
	})
	let listData : Ref<Array<childrenData>> = ref(props.data)
	const tmCascaderName = 'tmCascader'
	//保存的选中对象数据
	let save_value_obj : Ref<Array<childrenData>> = ref([])
	//当前选中的id数组。
	const _value : Ref<string | number> = ref('')
	const _idArrays : Ref<Array<string | number>> = ref([])
	const _idArrays_str = ref<string[]>([])
	const _nowActiveIndex = ref<number[]>([])
	const _valueArrays : Ref<Array<string>> = ref([]);

	const _fieldNames = computed(() => Object.assign({ label: 'dictValue', value: 'dictKey', children: 'children' }, props.fieldNames));


	//当前的层级
	const _activeIndex = ref(0)
	//下一步的层级。
	const _nowLevel = ref(0)
	const nodeLabel = computed(() => {
		if (props.fieldNames.bindLabel) {
			return props.fieldNames.bindLabel;
		}
		return props.fieldNames.label;
	});
	const nodeValue = computed(() => {
		if (props.fieldNames.bindValue) {
			return props.fieldNames.bindValue;
		}
		return props.fieldNames.value;
	});

	//查找节点路径。
	// 判断是父节点还是子节点，如果是父或者不存在的节点，不作操作。
	function initNode(once : boolean = false) {
		let listdata : any = uni.$tm.u.deepClone(props.data)
		let moisref = uni.$tm.u.deepClone(props.modelValue)
		
		let ls_ids = Array.isArray(moisref) ? moisref : []
		_value.value = ls_ids.length == 0 ? '' : ls_ids[ls_ids.length - 1]

		if (_value.value == '' || typeof _value.value == 'undefined') return
		let isParent = queryNodeIsParent(listdata, String(_value.value), nodeValue.value)

		//父节点不能选中。
		if (isParent) return
		let parentStr = getNodeRouterCustomStr(listdata, ls_ids, nodeValue.value)

		_idArrays.value = moisref
		if (parentStr.length > 0) {

			_valueArrays.value = parentStr.map((el : any) => el[nodeLabel.value]);
		}
		_activeIndex.value = _idArrays.value.length ? _idArrays.value.length - 1 : 0
		_nowLevel.value = _activeIndex.value
	}

	onMounted(() => {
		//初始化
		nextTick(() => getTreeData(true))
	})
	const getTreeData = (flag) => {
		if (!props.lazy) {
			//初始化
			initNode(flag);
			return;
		}
		let mySearchParams = Object.assign(props.searchParams, {
			tableName: 'sys_dict',
			resultList: [],
			queryList: [],
			pageNum: 1,
			pageSize: 20,
		});

		if (!mySearchParams.tableName) {
			mySearchParams.tableName = 'sys_dict';
		}
		let searchField = props.searchField;
		if (!searchField) {
			searchField = toLine(nodeLabel.value);
		}
		mySearchParams.keyName = nodeLabel.value;
		mySearchParams.valueName = nodeValue.value;
		mySearchParams.searchField = searchField;
		//mySearchParams.searchText = searchText;
		//mySearchParams[props.searchField] = searchText;
		if (props.queryParams) {
			mySearchParams = Object.assign(mySearchParams, props.queryParams);
		}
		let config : any = {};
		if (props.timeout && props.timeout > 0) {
			config.timeout = props.timeout;
		}
		let searchUrl = $api.common.getDictSearchData.url;
		if (props.funcCode) {
			let headers = { funcCode: props.funcCode };
			config.header = headers;
			searchUrl = $api.common.send.url + props.funcCode;
		} else {
			if (props.url) {
				searchUrl = props.url;
			} else if (props.dictField) {
				searchUrl = $api.common.send.url + 'dict0025';
				let headers = { funcCode: 'dict0025' };
				config.header = headers;
				mySearchParams.dictField = props.dictField;
			}
		}
		http
			.post(searchUrl, mySearchParams, config)
			.then((res : any) => {
				if (!Array.isArray(res.result)) {
					listData.value = res.result.treeList || [];
				} else {
					listData.value = res.result || [];
				}
				//初始化
				initNode(flag);
			})
			.catch(() => { });
	};
	provide(
		'tmCascaderValue',
		computed(() => _idArrays.value)
	)
	provide(
		'tmCascaderShowIndex',
		computed(() => _activeIndex.value)
	)

	function pushValue(key : childrenData, level : number, id : string | number, keyIndex : number) {

		if (_idArrays.value.length < level) {
			_idArrays.value.push(id)
			_idArrays_str.value.push(key[nodeLabel.value])
			_valueArrays.value.push(key[nodeLabel.value]);
			_nowActiveIndex.value.push(keyIndex)
		} else {
			_idArrays.value[level] = id
			_idArrays_str.value.splice(level, 1, key[nodeLabel.value])
			_valueArrays.value.splice(level, 1, key[nodeLabel.value])
			_nowActiveIndex.value[level] = keyIndex

			nextTick(() => {
				_idArrays.value = _idArrays.value.slice(0, level + 1)
				_idArrays_str.value = _idArrays_str.value.slice(0, level + 1)
				_valueArrays.value = _valueArrays.value.slice(0, level + 1)
				_nowActiveIndex.value = _nowActiveIndex.value.slice(0, level + 1)
			})
		}
	}

	async function addActiveIndex(level : number, childrenIndex : number, childrenData : childrenData) {
		if (typeof props.beforeCellClick === 'function') {
			uni.showLoading({ title: '...' })
			let p = await props.beforeCellClick(_nowActiveIndex.value, childrenIndex, childrenData)
			if (typeof p === 'function') {
				p = await props.beforeCellClick(_nowActiveIndex.value, childrenIndex, childrenData)
			}
			uni.hideLoading()
			if (!p) return
		}
		_activeIndex.value = level
		_nowLevel.value = level
	}

	function endSelected() {
		let str = '';
		if (_valueArrays.value && _valueArrays.value.length > 0) {
			if (props.showAllLevels) {
				str = _valueArrays.value.join(props.separator ? props.separator : '/');
			} else {
				str = _valueArrays.value[_valueArrays.value.length - 1];
			}
		}
		let value = null;
		if (_idArrays.value && _idArrays.value.length > 0) {
			if (props.retAllLevels) {
				value = _idArrays.value;
			} else {
				value = _idArrays.value[_idArrays.value.length - 1];
			}
		}
		emits('update:modelStr', str);
		emits('update:modelValue', value);
		nextTick(() => {
			emits('change', value,str);
		});
	}
	watch(
		() => props.modelValue,
		() => {
			if (props.modelValue.length == 0) {
				_value.value = ''
				save_value_obj.value = []
				_idArrays.value = []
				_idArrays_str.value = []
				_valueArrays.value = [];
				_activeIndex.value = 0
				_nowLevel.value = 0
				return
			}
			initNode()
		},
		{ deep: true }
	)
	// watch(
	//   () => props.data,
	//   () => {
	//     save_value_obj.value = [];
	//     _activeIndex.value = 0;
	//     _nowLevel.value = 0;
	//     _idArrays.value = [];
	// 	_idArrays_str.value = [];
	//   },
	//   { deep: true }
	// );
	/**
	 * 返回当前选中的数据对象数组。
	 */
	function getValueObject() {
		let pr = uni.$tm.u.deepClone(_idArrays.value)
		let [lastId] = pr.reverse()
		let ar = getNodeRouterData(uni.$tm.u.deepClone(props.data), String(lastId), [], nodeValue.value)
		return ar
	}
	/**
	 * 返回当前选中的数据字符串路径
	 */
	function getValueStr() : Array<string> {
		let ar : Array<childrenData> = getValueObject()
		let str = ar.map((el) => el[nodeLabel.value])
		return str
	}

	async function tabClick(index : number) {
		if (typeof props.beforeTabClick === 'function') {
			uni.showLoading({ title: '...' })
			let p = await props.beforeTabClick()
			if (typeof p === 'function') {
				p = await p()
			}
			uni.hideLoading()
			if (!p) return
		}
		_activeIndex.value = index
		emits('tab-click', index)
	}

	function reFresh(data : Array<childrenData> = []) {
		listData.value = []
		if (!Array.isArray(data)) {
			console.error('需要提供数组格式')
			return
		}
		listData.value = data.length > 0 ? data : props.data
	}
	defineExpose({
		pushValue,
		addActiveIndex,
		tmCascaderName,
		getValueStr,
		getValueObject,
		endSelected,
		reFresh
	})
</script>